/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ces31.ChineseDicesServer.RN;

import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import ces31.ChineseDicesCommon.ClienteInterface;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Imada
 */
public class RN_Rodada {

    /**
     * -> set variables
     * -> inicializaNovaRodada
     *
     * @param jogo
     * @param jogadores
     * @param firstPlayer
     */
    public RN_Rodada(RN_Jogo game, List<RN_Jogador> players, RN_Jogador firstPlayer) throws RemoteException {
        setJogo(game);
        setJogadores(players);
        setJogadorAtual(firstPlayer);
        //iniciarRodada();
    }

    /**
     * Start round with <tt>jogadores</tt> by:
     *  - sorting player's dices;
     *  - enabling first player entregarAfirmacaoParaAdversario();
     *
     * @param jogadores that will play.
     */
    public void iniciarRodada() throws RemoteException {
        System.out.println("Chegou aqui!Iniciar rodada");
        for (int i = 0; i < 2; i++) {
            RN_Jogador player = getJogadores().get(i);
            player.sortearDado();
        }
        atualizarJogadores();
        habilitarJogada(jogadorAtual);
    }

    /**
     * -> Sort jogadores' dices.
     * -> Collaborations:
     * [VF1]atualizarInformacoesJogador
     *
     */
    public void atualizarJogadores() throws RemoteException {
        for (int i = 0; i < 2; i++) {
            RN_Jogador player = getJogadores().get(i);
            player.getClienteInterface().atualizarInformacoesJogador(
                    player.getValorDosDados(),
                    oponente(player).getQuantidadeDeDados(),
                    getJogadorAtual().getNome());
        }
    }

    /**
     * -> Set jogadorAtual
     * -> Collaborations:
     * [VF1]habilitarJogada
     *
     */
    public void habilitarJogada(RN_Jogador player) throws RemoteException {
        System.out.println("Player a iniciar rodada" + player);
        setJogadorAtual(player);
        player.getClienteInterface().habilitarJogada();
    }

    /**
     * Send statment to all jogadores and wait enable other player's entregarAfirmacaoParaAdversario().
     * -> Set ultimaAfirmacao
     * -> Send statement and wait for next statement
     *
     */
    public void encaminharAfirmacao(ClienteInterface client, Integer quantity, Integer value) throws RemoteException {
        //Extract method: getPlayerFromClient()
        RN_Jogador player = getJogadores().get(0);
        if (getJogadores().get(1).getClienteInterface().equals(client)) {
            player = getJogadores().get(1);
        }

        Map<String, Integer> statement = new HashMap<String, Integer>();
        statement.put("quantity", quantity);
        statement.put("value", value);
        guardarUltimaAfirmacao(statement);
        broadcastAfirmacao(statement);
        habilitarJogada(oponente(player));
    }

    /**
     *  Receive doubt, ending current round.
     * -> Check winner
     *
     *  @return winner of the round.
     */
    public RN_Jogador verificarVencedorDaRodada() {
        RN_Jogador winner = verificaVencedor();
        winner.removerUmDado();
        return winner;
    }

    /*  TODO: Refactor... extract methods:
     *  - Boolean isLastStatementAcceptable
     *  - Map getDices
     *  - Player defineWinner
     */
    /**
     * -> Collaborations:
     * player.getDices().getValues()
     *
     * @return winner of the round.
     */
    private RN_Jogador verificaVencedor() {
        Map<Integer, Integer> dices = new HashMap<Integer, Integer>();
        for (int i = 1; i <= 6; i++) {
            dices.put(i, 0);
        }
        for (int i = 0; i < 2; i++) {
            Iterator<Integer> iterator = getJogadores().get(i).getValorDosDados().iterator();
            while (iterator.hasNext()) {
                Integer value = iterator.next();
//        for(Player player : getJogadores()){
//                for(Integer value : player.getDices().getValues()){
                dices.put(value, dices.get(value) + 1);
            }
        }
        RN_Jogador winner = getJogadorAtual();
        Integer maxQuantityAcceptable = dices.get(getUltimaAfirmacao().get("value"));
        if (getUltimaAfirmacao().get("value") != CORINGA) {
            maxQuantityAcceptable = maxQuantityAcceptable + dices.get(CORINGA);
        }
        if (getUltimaAfirmacao().get("quantity") <= maxQuantityAcceptable) {
            winner = oponente(winner);
        }
        return winner;
    }

    /**
     * Send <tt>statement<tt> to all jogadores in the jogo.
     * -> Collaborations:
     * [VF1]entregarAfirmacaoParaAdversario
     */
    private void broadcastAfirmacao(Map<String, Integer> statement) {
        for (RN_Jogador player : getJogadores()) {
            try {
                player.getClienteInterface().apresentarAfirmacao(statement.get("quantity"), statement.get("value"));
            } catch (RemoteException ex) {
                Logger.getLogger(RN_Rodada.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Returns other player (as there are two player playing).
     *
     * @return the other player in the jogo.
     */
    private RN_Jogador oponente(RN_Jogador player) {
        if (player.equals(getJogadores().get(0))) {
            return getJogadores().get(1);
        }
        return getJogadores().get(0);
    }


    /* Getters and Setters */
    public List<RN_Jogador> getJogadores() {
        return jogadores;
    }

    protected void setJogadores(List<RN_Jogador> players) {
        this.jogadores = players;
    }

    private void setJogadorAtual(RN_Jogador currentPlayer) {
        this.jogadorAtual = currentPlayer;
    }

    private RN_Jogador getJogadorAtual() {
        return this.jogadorAtual;
    }

    public RN_Jogo getJogo() {
        return jogo;
    }

    protected void setJogo(RN_Jogo game) {
        this.jogo = game;
    }

    private void guardarUltimaAfirmacao(Map<String, Integer> statement) {
        this.ultimaAfirmacao = statement;
    }

    private Map<String, Integer> getUltimaAfirmacao() {
        return this.ultimaAfirmacao;
    }
    
    private Map<String, Integer> ultimaAfirmacao;
    private RN_Jogador jogadorAtual;
    private List<RN_Jogador> jogadores;
    private RN_Jogo jogo;
    private final Integer CORINGA = 1;
}
